/**
 * Created by Jack Xue on 20101116
 */
package org.code.jack.jweberp.core;

import java.beans.PropertyDescriptor;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.apache.commons.beanutils.ConvertUtils;
import org.apache.log4j.Logger;
import org.code.jack.jweberp.dao.IPOLoadDao;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.util.StringUtils;
import org.springframework.web.context.ContextLoader;


/**
 * 使用WebForm来替代Struts的ActionForm,使其request中包含的视图层数据直接传递到PO中
 */
@SuppressWarnings("rawtypes")
public class WebForm {
	private static final Logger logger = Logger.getLogger(WebForm.class);

	/**
	 * 存放普通的字符串类型的参数值
	 */

	private Map textElement = new HashMap();

	/**
	 * 存放二进制类型的参数值
	 */
	private Map fileElement;

	/**
	 * 在视图层及逻辑层传输数据，把视图层的对象(View Object)传入程序对象(Program Object)中b
	 * 
	 * @param domain
	 *            赋值PO的目标对象
	 * @return 经过处理后，包含了视图层数据的一个POJO对象
	 */
	public Object form2Obj(Class domain) {
		try {
			return form2Obj(domain.newInstance(), false);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * 在视图层及逻辑层传输数据，把视图层的对象(View Object)传入程序对象(Program Object)中
	 * 
	 * @param domain
	 *            赋值PO的目标对象
	 * @param ignoreBlankString
	 *            是否忽略空字符串，特别当PO中的类型为非字符型的时候，此选项特别有用
	 * @return 经过处理后，包含了视图层数据的一个POJO对象
	 */
	public Object form2Obj(Class domain, boolean ignoreBlankString) {
		try {
			return form2Obj(domain.newInstance(), ignoreBlankString);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * 在视图层及逻辑层传输数据，把视图层的对象(View Object)传入程序对象(Program Object)中
	 * 
	 * @param domain
	 *            {要传入的目标对象}
	 * @return 经过处理后，包含了视图层数据的一个POJO对象
	 */
	public Object form2Obj(Object domain) {
		return form2Obj(domain, false);
	}

	/**
	 * @param obj
	 *            {要传入的目标对象}
	 * @param ignoreBlankString
	 *            {是否忽略空字符串，特别当PO中的类型为非字符型的时候，此选项特别有用}
	 * @return 经过处理后，包含了视图层数据的一个POJO对象
	 */
	@SuppressWarnings("unchecked")
	public Object form2Obj(Object obj, boolean ignoreBlankString) {
		Map<String, Object> propertys = parseForm2Obj(getTextElement(), obj, ignoreBlankString);
		BeanWrapper beanWrapper = new BeanWrapperImpl(obj);
		Iterator<Map.Entry<String, Object>> it = propertys.entrySet().iterator();
		while (it.hasNext()) {
			Map.Entry<String, Object> entry = (Map.Entry<String, Object>) it.next();
			beanWrapper.setPropertyValue(entry.getKey(), entry.getValue());
		}
		return obj;
	}

	public Map parseForm2Obj(Map map, Object obj, boolean ignoreBlankString) {
		Map<String, Object> ret = new HashMap<String, Object>();
		BeanWrapper bw = new BeanWrapperImpl(obj);
		PropertyDescriptor[] propertys = bw.getPropertyDescriptors();
		for (PropertyDescriptor property : propertys) {
			String propertyName = property.getName();
			if (!bw.isWritableProperty(propertyName)) {
				continue;
			}
			Object propertyValue = null;
			POLoad load = null;
			try {
				Field f = property.getWriteMethod().getDeclaringClass().getDeclaredField(propertyName);
				if (load == null)
					load = f.getAnnotation(POLoad.class);
			} catch (NoSuchFieldException e) {
			}
			if (load != null && !"".equals(load.name())) {
				// 使用这种方式得到Spring容器,性能很差
				// ApplicationContext context = new ClassPathXmlApplicationContext("classpath:application.xml");
				IPOLoadDao poLoadDao = (IPOLoadDao) ContextLoader.getCurrentWebApplicationContext().getBean("jpaPOLoadDao");
				if (poLoadDao != null && map.containsKey(load.name())) {
					Object rawObj = map.get(StringUtils.hasText(load.name()) ? load.name() : propertyName);
					// 要进行一个判断,有时视图层在无选择对象关联的情况下关联主键值则为空
					if (StringUtils.hasText((CharSequence) rawObj)) {
						logger.debug("成功加载注解POLoad所属属性的关联对象,关联ID为" + rawObj);
						propertyValue = poLoadDao.getEntity(property.getPropertyType(), (Serializable) ConvertUtils.convert(rawObj, load
								.getIdType()));
					}
				}
			} else {
				// 如果表单中没有PO对象属性所对应的值则直接进行跳转
				if (!map.containsKey(propertyName)) {
					continue;
				}
				Object value = map.get(propertyName);
				// ignoreBlankString是指是否忽略空字符串
				if (ignoreBlankString) {
					if (value != null && !"".equals(value)) {
						propertyValue = ConvertUtils.convert(value, property.getPropertyType());// 赋值时进行类型转换
						// BeanUtils.setProperty(targetDomain, propertyName, propertyValue);
					} else {
						continue;// 如果为空则直接进行跳转
					}
				} else {
					propertyValue = ConvertUtils.convert(value, property.getPropertyType());// 赋值时进行类型转换
				}
			}
			ret.put(propertyName, propertyValue);
		}
		return ret;
	}

	/**
	 * 获得表单中上传过来的二进制文件对象
	 * 
	 * @return 若有二进制文件，则返回具体的文件对象
	 */
	public Map getFileElement() {
		return fileElement;
	}

	/**
	 * 设置表单中的二进制文件数据对象
	 * 
	 * @param fileElement
	 *            二进制文件数据
	 */
	public void setFileElement(Map fileElement) {
		this.fileElement = fileElement;
	}

	/**
	 * 获取表单中所有文本性质的域内容对象
	 * 
	 * @return 表单中的所有文本性质的域对象
	 */
	public Map getTextElement() {
		return textElement;
	}

	/**
	 * 设置WebForm中文本域内容集
	 * 
	 * @param textElement
	 *            文本域的内容集合
	 */
	public void setTextElement(Map textElement) {
		this.textElement = textElement;
	}

	public Object get(String name) {
		if (textElement.containsKey(name)) {
			return textElement.get(name);
		} else {
			return fileElement.get("name");
		}
	}
}
